package com.fingard.dsp.bank.directbank.nnbill01.util;

import com.allinpay.ets.client.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.*;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import javax.net.ssl.SSLContext;
import java.security.KeyStore;
import java.security.cert.X509Certificate;

public class HttpsClientFactory {
    /**
     * 客户端证书
     */
    private KeyStore keyStore;

    /**
     * 服务端证书
     */
    private KeyStore trustStore;

    /**
     * 客户端证书密码
     */
    private String keyStorePwd;

    /**
     * 服务端证书密码
     */
    private String trustStorePwd;

    /**
     * 连接超时时间
     */
    private int soTimeout;

    /**
     * 连接建立时间
     */
    private int connTimeout;

    /**
     * SSL版本
     */
    private String SSLVersion;

    /**
     * 根据证书创建HttpsClient<br>
     * 必须配置：trustStorePath,trustStorePwd(单项认证还是双向认证 是由服务器决定的)<br>
     * 双向认证还需配置:keyStorePath,keyStorePwd<br>
     * 
     * @return
     * @throws Exception
     */
    public CloseableHttpClient createSSLClient() throws Exception {
        SSLContext sslContext = null;
        SSLContextBuilder builder = SSLContexts.custom();
        // 加载客户端证书
        if(keyStore != null) {
            if(StringUtil.isEmpty(keyStorePwd)) {
                builder = builder.loadKeyMaterial(keyStore, null);
            }else {
                builder = builder.loadKeyMaterial(keyStore, keyStorePwd.toCharArray());
            }
        }
        // 加载服务端证书
        if(trustStore != null) {
            sslContext = builder.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
        }else {
            /**
             * 客户端验证服务端
             */
            sslContext = builder.loadTrustMaterial(null, new TrustStrategy(){
                // 信任所有
                @Override
                public boolean isTrusted(X509Certificate[] xcs, String string) {
                    return true;
                }
            }).build();
        }
        SSLConnectionSocketFactory sslsf = getConnectionSocketFactory(sslContext);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(Integer.valueOf(soTimeout))
                .setConnectTimeout(Integer.valueOf(connTimeout)).build();
        return HttpClients.custom().setDefaultRequestConfig(requestConfig).setSSLSocketFactory(sslsf).build();
    }

    private SSLConnectionSocketFactory getConnectionSocketFactory(SSLContext sslContext) {
        if(StringUtils.isBlank(SSLVersion)) {
            return new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        }else {
            return new SSLConnectionSocketFactory(sslContext, new String[] { SSLVersion }, null,
                    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        }
    }

    public String getSSLVersion() {
        return SSLVersion;
    }

    public void setSSLVersion(String sSLVersion) {
        SSLVersion = sSLVersion;
    }

    public void setKeyStore(KeyStore keyStore) {
        this.keyStore = keyStore;
    }

    public void setTrustStore(KeyStore trustStore) {
        this.trustStore = trustStore;
    }

    public String getKeyStorePwd() {
        return keyStorePwd;
    }

    public void setKeyStorePwd(String keyStorePwd) {
        this.keyStorePwd = keyStorePwd;
    }

    public String getTrustStorePwd() {
        return trustStorePwd;
    }

    public void setTrustStorePwd(String trustStorePwd) {
        this.trustStorePwd = trustStorePwd;
    }

    public int getSoTimeout() {
        return soTimeout;
    }

    public void setSoTimeout(int soTimeout) {
        this.soTimeout = soTimeout;
    }

    public int getConnTimeout() {
        return connTimeout;
    }

    public void setConnTimeout(int connTimeout) {
        this.connTimeout = connTimeout;
    }

    public KeyStore getKeyStore() {
        return keyStore;
    }

    public KeyStore getTrustStore() {
        return trustStore;
    }
}
